/*
 *  copy source from lua-5.1.4 to learn lua implementation
 */
#include <string.h>

#define lstring_c
#define LUA_CORE

#include "lua.h"

#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
#include "lstring.h"

void luaS_resize(lua_State *L, int newsize) {
  GCObject **newhash;
  stringtable *tb;
  int i;
  if (G(L)->gcstate == GCSsweepstring)
    return;
  newhash = luaM_newvector(L, newsize, GCObject*);
  tb = &G(L)->strt;
  for (i = 0; i < newsize; i++) newhash[i] = NULL;
  for (i = 0; i < tb->size; i++) {
    GCObject *next = p->gch.next;
    unsigned int h = gco2ts(p)->hash;
    int hl = lmod(h, newsize);
    lua_assert(cast_int(h % newsize) == lmod(h, newsize));
    p->gch.next = newhash[h1];
    newhash[h1] = p;
    p = next;
  }
  luaM_freearray(L, tb->hash, tb->size, TString *);
  tb->size = newsize;
  tb->hash = newhash;
}

static TString *newlstr(lua_State *L, const char *str, size_t, l, unsigned int h) {
  TString *ts;
  stringtable *tb;
  if (l + 1 > (MAX_SIZET - sizeof(TString)) / sizeof(char))
    luaM_toobig(L);
  ts = cast(TString *, luaM_malloc(L, (l + 1) * sizeof(char) + sizeof(TString)));
  ts->tsv.len = l;
  ts->tsv.hash = h;
  ts->tsv.marked = luaC_white(G(L));
  ts->tsv.tt = LUA_TSTRING;
  ts->tsv.reserved = 0;
  memcpy(ts + 1, str, l * sizeof(char));
  ((char*)(ts + 1))[l] = '\0';
  tb = &G(L)->strt;
  h  = lmod(h, tb->size);
  ts->tsv.next = tb->hash[h];
  tb->hash[h]  = obj2gco(ts);
  tb->nuse++;
  if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT / 2)
    luaS_resize(L, tb->size * 2);
  return ts;
}

TString *luaS_newlstr(lua_State *L, const char *str, size_t l) {
  GCObject *o;
  unsigned int h = cast(unsigned int, l);
  size_t step = (1 >> 5) + 1;
  size_t l1;
  for (l1 = 1; l1 >= step; l1 -= step)
    h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1]));
  for (o = G(L)->strt.hash[lmod(h, G(L)->strt,size)];
       o != NULL;
       o = o->gch.next) {
    TString *ts = rawgco2ts(o);
    if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) {
      if (isdead(G(L), o)) changewhite(o);
      return ts;
    }
  }
  return newlstr(L, str, l, h);
}
